import numpy as np
import os
from matplotlib import pyplot
from numpy import interp
# import matplotlib.pyplot as plt
import sklearn, tensorflow
import xlsxwriter
import xlrd
from sklearn import svm  # , grid_search
from sklearn.preprocessing import LabelEncoder
from sklearn.svm import LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.decomposition import PCA
from sklearn import metrics
from sklearn import model_selection

from sklearn.model_selection import train_test_split, KFold
from sklearn.calibration import CalibratedClassifierCV
from sklearn.model_selection import StratifiedKFold
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, auc
from sklearn.metrics import precision_recall_curve
import gzip
import pandas as pd
import pdb
import random
from random import randint
import scipy.io

from keras.layers import Input, Dense
from keras.engine.training import Model
from keras.models import Sequential, model_from_config, Model
from keras.layers.core import Dropout, Activation, Flatten
from keras.layers.normalization import BatchNormalization
from keras.layers.advanced_activations import PReLU
from keras.utils import np_utils, generic_utils
from keras.optimizers import SGD, RMSprop, Adadelta, Adagrad, Adam
from keras.layers import normalization
from keras.layers.embeddings import Embedding
from keras import regularizers
from keras.constraints import maxnorm


def calculate_performace(test_num, pred_y, labels):  # pred_y = proba, labels = real_labels
    tp = 0
    fp = 0
    tn = 0
    fn = 0
    for index in range(test_num):
        if labels[index] == 1:
            if labels[index] == pred_y[index]:
                tp = tp + 1
            else:
                fn = fn + 1
        else:
            if labels[index] == pred_y[index]:
                tn = tn + 1
            else:
                fp = fp + 1

    acc = float(tp + tn) / test_num

    if tp == 0 and fp == 0:
        precision = 0
        MCC = 0
        f1_score = 0
        sensitivity = float(tp) / (tp + fn)
        specificity = float(tn) / (tn + fp)
    else:
        precision = float(tp) / (tp + fp)
        sensitivity = float(tp) / (tp + fn)
        specificity = float(tn) / (tn + fp)
        MCC = float(tp * tn - fp * fn) / (np.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn)))
        f1_score = float(2 * tp) / ((2 * tp) + fp + fn)

    return acc, precision, sensitivity, specificity, MCC, f1_score


def transfer_array_format(data):  # data=X  , X=circRNA和疾病的综合特征矩阵
    formated_matrix1 = []
    formated_matrix2 = []

    for val in data:
        # formated_matrix1.append(np.array([val[0]]))
        formated_matrix1.append(val[0])  # 包含circRNA的特征 ?
        formated_matrix2.append(val[1])  # 包含疾病的特征 ?

    return np.array(formated_matrix1), np.array(formated_matrix2)


def preprocess_labels(labels, encoder=None, categorical=True):
    if not encoder:
        encoder = LabelEncoder()  # 获取一个标签编码器labelEncoder
        encoder.fit(labels)  # 训练labelEncoder
    y = encoder.transform(labels).astype(np.int32)  # 使用训练好的labelEncoder对原数据进行编码
    if categorical:
        y = np_utils.to_categorical(y)  # 用于分类，将标签转化为one-hot编码
    return y  # 返回编码后的标签和编码器


def DNN():
    model = Sequential()
    model.add(Dense(input_dim=128, output_dim=600,kernel_regularizer=regularizers.l2(0.008))) # 0.008
    model.add(Activation('relu'))
    model.add(Dropout(0.2))

    model.add(Dense(input_dim=600, output_dim=300, init='glorot_normal', kernel_regularizer=regularizers.l2(0.008))) # Hidden layer1
    model.add(Activation('relu'))
    model.add(Dropout(0.2))

    model.add(Dense(input_dim=300, output_dim=100, kernel_regularizer=regularizers.l2(0.008)))  # ,init='glorot_normal'))  # Hidden layer 2
    model.add(Activation('relu'))
    model.add(Dropout(0.2))

    model.add(Dense(input_dim=100, output_dim=2))  # ,init='glorot_normal'))  #  Output layer
    model.add(Activation('sigmoid'))
    # sgd = SGD(l2=0.0,lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
    adadelta = Adadelta(lr=1.0, rho=0.95, epsilon=1e-08)
    model.compile(loss='binary_crossentropy', optimizer=adadelta)
    return model


def transfer_label_from_prob(proba):
    label = [1 if val >= 0.5 else 0 for val in proba]
    return label

